<?php


namespace App\Repositories;


use App\Jobs\OrderGetExpress;
use App\Libraries\Express\Client;
use App\Models\Order as Model;
use App\Models\OrderProduct;
use App\Traits\CodeTrait;
use App\Traits\Logs;
use Exception;
use Illuminate\Support\Facades\DB;
use LTools\Repositories\RepositoryAbstract;
use Throwable;

class Order extends RepositoryAbstract
{
    use CodeTrait, Logs;

    /**
     * Order constructor.
     * @param Model $model
     * @author luffyzhao@vip.126.com
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * @param array $attributes
     * @param int|null $perPage
     * @param array $columns
     * @param string $pageName
     * @param int|null $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['customer', 'express', 'customs'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param array $attributes
     * @return Model|bool|\Illuminate\Database\Eloquent\Model
     * @throws Exception
     * @author luffyzhao@vip.126.com
     */
    public function create(array $attributes = [])
    {
        $customerCode = \App\Models\Customer::query()->where('id', '=', $attributes['customer_id'])->value('code');
        $attributes['code'] = $this->unique(11, $customerCode . 'SO');

        $attributes = $this->completion($attributes);

        try {
            /** @var Model $model */
            $model = parent::create($attributes);
        } catch (Exception $exception) {
            if($exception->getCode()=== '23000'){
                throw new Exception(sprintf('订单号 %s 已存在', $attributes['number']));
            }
            throw new Exception(sprintf('订单号 %s 创建失败，请检查参数！', $attributes['number']));
        }


        foreach ($attributes['products'] as $product) {
            $model->products()->create(
                collect($product)->only(['product_id', 'attribute', 'expire', 'quantity', 'price', 'expiry'])->toArray()
            );
        }

        $this->recordLogs($model, '创建订单成功');

        return $model;
    }

    /**
     * @param $id
     * @return mixed
     */
    public function edit($id)
    {
        return $this->model->with(['products.product'])->findOrFail($id, ['id', 'number', 'customer_id', 'express_id', 'freight', 'buyer_name', 'receiving_name', 'receiving_phone', 'buyer_type', 'buyer_number', 'buyer_telephone', 'areas', 'address', 'remark', 'original_number', 'ebc_code', 'ebc_name', 'ebp_code', 'ebp_name']);
    }

    /**
     * @param $id
     * @param array $values
     * @return bool|\Illuminate\Database\Eloquent\Model
     * @throws Throwable
     */
    public function update($id, array $values)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 0) {


            // 参数整理
            $values['customer_id'] = $model->getAttribute('customer_id');
            $values = $this->completion($values);

            $model->fill($values)->saveOrFail();

            // 产品更新
            $model->products()->delete();
            foreach ($values['products'] as $product) {
                $model->products()->create(
                    collect($product)->only(['product_id', 'attribute', 'expire', 'quantity', 'price', 'expiry'])->toArray()
                );
            }

            $this->recordLogs($model, '修改订单成功');
            return $model;
        }
        throw new Exception("订单状态不正确");
    }


    /**
     * @param $id
     * @return Model
     * @throws Exception
     * @throws Throwable
     */
    public function confirm($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
        if ($model->getAttribute('status') === 0) {

            $blacklistCount = $model->express->blacklist()
                ->where('address', '=', $model->getAttribute('areas')[2])
                ->count();
            if ($blacklistCount) {
                throw new Exception("该运输方式不支持[{$model->getAttribute('areas')[2]}]");
            }

            $model->setAttribute('status', 1);
            $model->saveOrFail();

            $model->loadMissing(['products', 'express']);

            $model->products->each(function (OrderProduct $item) {
                app(ProductInventory::class)->lock($item->getAttribute('product_id'), $item->getAttribute('quantity'));
            });

            OrderGetExpress::dispatch($model->getKey());
            return $model;
        }
        throw new Exception("订单状态不正确");
    }

    /**
     * @param $id
     * @return Model
     * @throws Exception
     * @throws Throwable
     */
    public function express($id)
    {
        /** @var Model $model */
        $model = $this->find($id);
        $client = new Client($model);
        try {
            $response = $client->create();
        } catch (Exception|Throwable $exception) {
            $this->recordLogs($model, "订单获取物流信息失败: [{$exception->getMessage()}]");
            throw new Exception($exception->getMessage());
        }
        /** 这个要上锁 */
        DB::transaction(function () use ($id, $response) {
            /** @var Model $model */
            $model = $this->model->newQuery()->where('id', '=', $id)->lockForUpdate()->first();
            if ($model->getAttribute('status') === 1) {
                $model->setAttribute('express_code', $response->getCode());
                $model->setAttribute('status', 3);
                $model->saveOrFail();

                $model->config()->create([
                    'key' => 'express_pdf',
                    'value' => $response->getResponse()
                ]);

                $this->recordLogs($model, "订单获取物流信息成功");
            }
        });

        app(OrderCustoms::class)->create(['order_id' => $id]);

        return $model;
    }

    /**
     * 创建订单时一些默认参数
     * @param array $attributes
     * @return array
     */
    protected function completion(array $attributes)
    {
        $attributes['weight'] = 0;
        $attributes['net_weight'] = 0;
        foreach ($attributes['products'] as $key => $product) {
            /** @var \App\Models\Product $productModel */
            $productModel = \App\Models\Product::query()
                ->where('status', '=', 3)
                ->where('code', '=', $product['code'])
                ->where('customer_id', '=', $attributes['customer_id'])
                ->firstOrFail();

            // 毛重
            $attributes['weight'] += $productModel['gross_weight'] * $product['quantity'];
            $attributes['net_weight'] += $productModel->customs->getAttribute('net_weight') * $product['quantity'];
            // 产品 code 转 id
            $attributes['products'][$key]['product_id'] = $productModel->getKey();
        }

        $productCollect = collect($attributes['products']);
        // 原始单号
        if (empty($attributes['original_number'])) {
            $attributes['original_number'] = $attributes['number'];
        }
        // 总价
        $attributes['price'] = $productCollect->sum(function ($item) {
            return $item['price'] * $item['quantity'];
        });


        return $attributes;
    }


    /**
     * @param array $attributes
     * @return Model
     * @throws Throwable
     */
    public function createForApi(array $attributes = [])
    {
        /** @var Model $model */
        $model = $this->create($attributes);
        return $this->confirm($model->getKey());
    }


    /**
     * @param array $body
     * @return void
     * @throws Exception
     */
    public function cancelForApi(array $body)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->where('number', '=', $body['number'])
            ->where('customer_id', '=', request()->input('customer_id'))->first();
        if(is_null($model)){
            throw new Exception('订单不存在');
        }
        // 上锁
        $model = $this->model->newQuery()->lockForUpdate()->where($model->getKeyName(), '=', $model->getKey())->first();

        switch ($model->getAttribute('status')){
            case 4: // 拦截
                $model->setAttribute('intercept_status', 1);
                $model->saveOrFail();
                break;
            case 3: // 直接取消
            case 1:
                // 解锁
                $model->products->each(function (OrderProduct $item) {
                    app(ProductInventory::class)->unLock($item->getAttribute('product_id'), $item->getAttribute('quantity'));
                });
                $model->setAttribute('status', -1);
                $model->saveOrFail();
                break;
            case -1:
                throw new Exception('订单已取消，不能拦截！');
            case 5:
                throw new Exception('订单已发货，不能拦截！');
        }




    }


}
